package com.mybatis_demo.frame.session.factory;

import com.mybatis_demo.frame.session.config.Configuration;
import com.mybatis_demo.frame.session.mapping.SqlMap;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SqlSessionFactoryBuilder {
    /**
     * 默认配置文件在resources目录下
     */
    public SqlSessionFactory build(){
        InputStream inputStream = SqlSessionFactory.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
        return build(inputStream);
    }

    /**
     *  想改位置
     */
    public SqlSessionFactory build(String path){
        InputStream inputStream = SqlSessionFactory.class.getClassLoader().getResourceAsStream(path);
        return build(inputStream);
    }

    /**
     *  给我一个流
     */
    public SqlSessionFactory build(InputStream inputStream){
        //开始解析dom4j
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);
            //....数据连接池的相关解析
            DataSource dataSource = loadDataSource(document);

            //接下来做sql语句相关解析
            Map<String, SqlMap> sqlMaps = loadSqls(document);

            Configuration configuration = new Configuration();
            configuration.setDataSource(dataSource);

            configuration.setSqlMaps(sqlMaps);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactory();
            sqlSessionFactory.setConfiguration(configuration);
            return sqlSessionFactory;
        } catch (DocumentException e) {
            e.printStackTrace();
            return null;
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {}
        }
    }

    /**
     * 解析sql
     * @return
     */
    private Map<String, SqlMap> loadSqls(Document document) {
        //获取核心配置文件mapper元素
        List<Element> list = document.selectNodes("//mapper");
        Map<String, SqlMap> sqlMaps = new HashMap<>();
        for (Element element : list) {
            //获取元素的resource属性， 代表另外配置文件的位置
            String location = element.attributeValue("resource");
            loadMapperXMl(location, sqlMaps);
        }
        return sqlMaps;
    }

    private void loadMapperXMl(String location,Map<String, SqlMap> sqlMaps) {
        SAXReader saxReader = new SAXReader();
        try {
            Document doc = saxReader.read(SqlSessionFactoryBuilder.class.getClassLoader().getResourceAsStream(location));
            //获取namespace属性值
            String namespace = doc.getRootElement().attributeValue("namespace");
            List<Element> selects = doc.selectNodes("//select");
            //遍历所有select元素
            for (Element select : selects) {
                String id = select.attributeValue("id");
                String sql = select.getTextTrim();
                String key = namespace +"." + id;
                String resultType = select.attributeValue("resultType");
                Class<?> aClass = Class.forName(resultType);
                //放到map集合
                sqlMaps.put(key,new SqlMap(sql,aClass));
            }
        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接池
     */
    private DataSource loadDataSource(Document document) {
        List<Element> list = document.selectNodes("//property");

        //hikari连接池的配置信息对象，将解析出来的信息设置给该对象
        HikariConfig config = new HikariConfig();
        for (Element element : list) {
            String name = element.attributeValue("name");
            if("driver".equals(name)){
                //拿到name = driver标签中的value属性值
                String value = element.attributeValue("value");
                config.setDriverClassName(value);
            }
            if("url".equals(name)){
                //拿到name = driver标签中的value属性值
                String value = element.attributeValue("value");
                config.setJdbcUrl(value);
            }
            if("username".equals(name)){
                //拿到name = driver标签中的value属性值
                String value = element.attributeValue("value");
                config.setUsername(value);
            }
            if("password".equals(name)){
                //拿到name = driver标签中的value属性值
                String value = element.attributeValue("value");
                config.setPassword(value);
            }
        }
        //获取hikari连接池配置对象
        HikariDataSource hikariDataSource = new HikariDataSource(config);
        return hikariDataSource;
    }
}
